// Copyright (c) 2018 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_
#define STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_

#include <type_traits>
#include <utility>

namespace leveldb
{

    // Wraps an instance whose destructor is never called.
    //
    // This is intended for use with function-level static variables.
    template <typename InstanceType>
    class NoDestructor
    {
    public:
        template <typename... ConstructorArgTypes>
        explicit NoDestructor(ConstructorArgTypes &&...constructor_args)
        {
            static_assert(sizeof(instance_storage_) >= sizeof(InstanceType),
                          "instance_storage_ is not large enough to hold the instance");
            static_assert(
                alignof(decltype(instance_storage_)) >= alignof(InstanceType),
                "instance_storage_ does not meet the instance's alignment requirement");
            new (&instance_storage_)
                InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...);
        }

        ~NoDestructor() = default;

        NoDestructor(const NoDestructor &) = delete;
        NoDestructor &operator=(const NoDestructor &) = delete;

        InstanceType *get()
        {
            return reinterpret_cast<InstanceType *>(&instance_storage_);
        }

    private:
        typename std::aligned_storage<sizeof(InstanceType),
                                      alignof(InstanceType)>::type instance_storage_;
    };

} // namespace leveldb

#endif // STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_
